/*
 * Copyright 2008 Lucas Tan.
 * This copyright notice must always remain intact whenever you use or distribute 
 * the source code contained in this file.
 * Any usage of any code in this file, either in derived work or
 * through the use of external linkage,
 * must always be credited with the author's name.
 * 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 * 
 * */
using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Security.Cryptography;

namespace PassKeeper.Cryptography
{

	///
	/// <summary>
	/// An implementation of the Advanced Encryption Standard (AES) in managed code. 
	/// This class cannot be inherited.
	/// </summary>
	/// <remarks>This implementation conforms to the FIPS-197 specification at
	/// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
	/// </remarks>
	///
	public sealed class AESManaged : AES
	{
		public AESManaged()
			: base()
		{
			/*do nothing.*/
		}
		
		/// <summary>
		/// Creates an <see cref="ICryptoTransform"/> interface object that can be used
		/// to encrypt data.
		/// </summary>
		/// <param name="rgbKey">An array of bytes that represent the key.</param>
		/// <param name="rgbIV">An array of bytes that represent the initialization vector (IV).</param>
		/// <returns>An <see cref="ICryptoTransform"/> interface that can be used to encrypt data.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="rgbKey"/> is null -or- <paramref name="rgbIV"/> is null
		/// when it is required.</exception>
		/// <exception cref="ArgumentException">
		/// The <see cref="CipherMode"/> or <see cref="PaddingMode"/> assigned to this object
		/// is not supported. 
		/// <para>-or- Size of <paramref name="rgbKey"/> is not 128, 192, or 256 bits.</para> 
		/// <para>-or- Size of <paramref name="rgbIV"/> is not 128 bits when it is required.</para></exception>
		public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
		{
			/*They will check the params for us.*/
			return new AESManagedTransform(true, this.Padding, this.Mode, rgbKey, rgbIV);
		}

		/// <summary>
		/// Creates an <see cref="ICryptoTransform"/> interface object that can be used
		/// to decrypt data.
		/// </summary>
		/// <param name="rgbKey">An array of bytes that represent the key.</param>
		/// <param name="rgbIV">An array of bytes that represent the initialization vector (IV).</param>
		/// <returns>An <see cref="ICryptoTransform"/> interface that can be used to decrypt data.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="rgbKey"/> is null -or- <paramref name="rgbIV"/> is null
		/// when it is required.</exception>
		/// <exception cref="ArgumentException">
		/// The <see cref="CipherMode"/> or <see cref="PaddingMode"/> assigned to this object
		/// is not supported. 
		/// <para>-or- Size of <paramref name="rgbKey"/> is not 128, 192, or 256 bits.</para> 
		/// <para>-or- Size of <paramref name="rgbIV"/> is not 128 bits when it is required.</para></exception>
		public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
		{
			/*They will check the params for us.*/
			return new AESManagedTransform(false, this.Padding, this.Mode, rgbKey, rgbIV);
		}

		public override void GenerateIV()
		{
			if (this.IVValue != null)
			{
				Array.Clear(this.IVValue, 0, this.IVValue.Length);
			}

			this.IVValue = new byte[this.BlockSizeValue / 8];
			RNG.GetBytes(this.IVValue);
		}

		public override void GenerateKey()
		{
			if (this.KeyValue != null)
			{
				Array.Clear(this.KeyValue, 0, this.KeyValue.Length);
			}

			this.KeyValue = new byte[this.KeySizeValue / 8];
			RNG.GetBytes(this.KeyValue);
		}
	}
}
